home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / Command.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  14.0 KB  |  518 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <windows.h>
  19.  
  20. #include "PositionControl.h"
  21.  
  22. #include "InputFile.h"
  23. #include "AudioSource.h"
  24. #include "VideoSource.h"
  25. #include "AVIOutput.h"
  26. #include "AVIOutputWAV.h"
  27. #include "AVIOutputStriped.h"
  28. #include "Dub.h"
  29. #include "Error.h"
  30. #include "FrameSubset.h"
  31.  
  32. #include "mpeg.h"
  33. #include "gui.h"
  34. #include "prefs.h"
  35. #include "command.h"
  36.  
  37. ///////////////////////////////////////////////////////////////////////////
  38.  
  39. extern HWND                    g_hWnd;
  40. extern DubOptions            g_dubOpts;
  41. extern HDC                    hDCWindow;
  42. extern HDRAWDIB                hDDWindow;
  43.  
  44. InputFile            *inputAVI                = NULL;
  45. AVIOutput            *outputAVI                = NULL;
  46. InputFileOptions    *g_pInputOpts            = NULL;
  47.  
  48. VideoSource            *inputVideoAVI            = NULL;
  49. AudioSource            *inputAudio                = NULL;
  50. AudioSource            *inputAudioAVI            = NULL;
  51. AudioSource            *inputAudioWAV            = NULL;
  52. FrameSubset            *inputSubset            = NULL;
  53.  
  54. int                     audioInputMode = AUDIOIN_AVI;
  55.  
  56. IDubber                *g_dubber                = NULL;
  57.  
  58. COMPVARS            g_Vcompression;
  59. WAVEFORMATEX        *g_ACompressionFormat        = NULL;
  60. DWORD                g_ACompressionFormatSize    = 0;
  61.  
  62. BOOL                g_drawDecompressedFrame    = FALSE;
  63. BOOL                g_showStatusWindow        = TRUE;
  64. BOOL                g_syncroBlit            = FALSE;
  65. BOOL                g_vertical                = FALSE;
  66.  
  67. ///////////////////////////////////////////////////////////////////////////
  68.  
  69. void InitDubAVI(char *szFile, int fAudioOnly, DubOptions *quick_options, int iPriority=0, bool fPropagateErrors = false, long lSpillThreshold=0, long lSpillFrameThreshold=0);
  70.  
  71. void SetAudioSource() {
  72.     switch(audioInputMode) {
  73.     case AUDIOIN_NONE:        inputAudio = NULL; break;
  74.     case AUDIOIN_AVI:        inputAudio = inputAudioAVI; break;
  75.     case AUDIOIN_WAVE:        inputAudio = inputAudioWAV; break;
  76.     }
  77. }
  78.  
  79. void OpenAVI(char *szFile, int iFileType, bool fExtendedOpen, bool fQuiet, bool fAutoscan, const char *pInputOpts) {
  80.     CloseAVI();
  81.  
  82.     // Reset dub option parameters.
  83.  
  84.     g_dubOpts.video.lStartOffsetMS = g_dubOpts.video.lEndOffsetMS = 0;
  85.  
  86.     try {
  87.         HWND hWndPosition = GetDlgItem(g_hWnd, IDC_POSITION);
  88.  
  89.         // attempt to determine input file type
  90.  
  91.         if (iFileType == FILETYPE_AUTODETECT || iFileType == FILETYPE_AUTODETECT2) {
  92.             HANDLE hFile;
  93.             char buf[64];
  94.             DWORD dwActual;
  95.  
  96.             memset(buf, 0, sizeof buf);
  97.  
  98.             hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  99.  
  100.             if (INVALID_HANDLE_VALUE == hFile)
  101.                 throw MyWin32Error("Can't open \"%s\": %%s", GetLastError(), szFile);
  102.  
  103.             if (!ReadFile(hFile, buf, 64, &dwActual, NULL))
  104.                 throw MyWin32Error("Error reading \"%s\": %%s", GetLastError(), szFile);
  105.  
  106.             // The Avisynth script:
  107.             //
  108.             //    Version
  109.             //
  110.             // is only 9 bytes...
  111.  
  112.             if (!dwActual)
  113.                 throw MyError("Can't read \"%s\": The file is empty).", szFile);
  114.  
  115.             CloseHandle(hFile);
  116.  
  117.             // 'RIFF' <size> 'AVI ' -> AVI
  118.             // 'RIFF' <size> 'CDXA' -> VideoCD stream
  119.             // 00 00 01 b3 -> MPEG video stream (video sequence start packet)
  120.             // 00 00 01 ba -> Interleaved MPEG
  121.             // '#str' -> stripe
  122.             // 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C
  123.             //        ->  (no this is not a joke)
  124.             // PK 03 04 -> Zip file
  125.  
  126.             const static unsigned char asf_sig[]={
  127.                 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11,
  128.                 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
  129.             };
  130.  
  131.  
  132.             if (*(long *)(buf+0)=='FFIR' && *(long *)(buf+8)==' IVA')
  133.                 iFileType = FILETYPE_AVI;
  134.             else if (*(long *)(buf+0)=='FFIR' && *(long *)(buf+8)=='AXDC')
  135. //                throw MyError("\"%s\" is a VideoCD stream that Windows has wrapped in a RIFF/CDXA file, which VirtualDub cannot read. You will need a utility "
  136. //                            "such as VCDGear to convert this back to a regular MPEG stream.", szFile);
  137.                 iFileType = FILETYPE_MPEG;
  138.             else if (*(long *)(buf+0) == 0x04034b50)
  139.                 throw MyError("\"%s\" is a Zip file!  Try unzipping it.", szFile);
  140.             else if (*(long *)(buf+0) == 0xba010000 || *(long *)(buf+0)==0xb3010000)
  141.                 iFileType = FILETYPE_MPEG;
  142.             else if (*(long *)buf == 'rts#')
  143.                 iFileType = FILETYPE_STRIPEDAVI;
  144.             else if (!memcmp(buf, asf_sig, 16)) {
  145.                 iFileType = FILETYPE_ASF;
  146.             } else {
  147.  
  148.                 // Last ditch: try AVIFile.  This will make Ben happy. :)
  149.  
  150.                 PAVIFILE paf;
  151.                 HRESULT hr = AVIFileOpen(&paf, szFile, OF_READ, NULL);
  152.  
  153.                 if (hr)
  154.                     throw MyError("Cannot determine file type of \"%s\"", szFile);
  155.  
  156.                 AVIFileRelease(paf);
  157.  
  158.                 iFileType = FILETYPE_AVICOMPAT;
  159.             }
  160.         }
  161.  
  162.         // open file
  163.  
  164.         switch(iFileType) {
  165.         case FILETYPE_AVI:
  166.         case FILETYPE_STRIPEDAVI:
  167.             inputAVI = new InputFileAVI(false);
  168.             if (fAutoscan)
  169.                 ((InputFileAVI *)inputAVI)->EnableSegmentAutoscan();
  170.             break;
  171.         case FILETYPE_AVICOMPAT:
  172.             inputAVI = new InputFileAVI(false);
  173.             break;
  174.         case FILETYPE_MPEG:
  175.             inputAVI = CreateInputFileMPEG();
  176.             break;
  177.         case FILETYPE_ASF:
  178. //            throw MyError("ASF file support has been removed at the request of Microsoft.");
  179.             throw MyError("Not supported: Microsoft owns US patent #6,041,345 on the ASF file format, preventing "
  180.                         "third-party applications from extracting data from ASF files. ASF file format support "
  181.                         "was removed as of V1.3d at the request of Microsoft and to avoid patent "
  182.                         "infringement claims, and as such VirtualDub no longer supports ASF. Please "
  183.                         "do not ask for versions that do.");
  184.             break;
  185.         }
  186.  
  187.         if (!inputAVI) throw MyMemoryError();
  188.  
  189.         if (fQuiet)
  190.             inputAVI->setAutomated(true);
  191.  
  192.         // Extended open?
  193.  
  194.         if (fExtendedOpen) {
  195.             g_pInputOpts = inputAVI->promptForOptions(g_hWnd);
  196.         } else if (pInputOpts)
  197.             g_pInputOpts = inputAVI->createOptions(pInputOpts);
  198.  
  199.         if (g_pInputOpts) inputAVI->setOptions(g_pInputOpts);
  200.  
  201.         if (iFileType == FILETYPE_AVICOMPAT)
  202.             ((InputFileAVI *)inputAVI)->ForceCompatibility();
  203.  
  204.  
  205.         if (iFileType == FILETYPE_STRIPEDAVI) {
  206.             ((InputFileAVI *)inputAVI)->InitStriped(szFile);
  207.         } else
  208.             inputAVI->Init(szFile);
  209.  
  210.         inputAudioAVI = inputAVI->audioSrc;
  211.         inputVideoAVI = inputAVI->videoSrc;
  212.  
  213.         if (!inputVideoAVI->setDecompressedFormat(24))
  214.             if (!inputVideoAVI->setDecompressedFormat(32))
  215.                 if (!inputVideoAVI->setDecompressedFormat(16))
  216.                     inputVideoAVI->setDecompressedFormat(8);
  217.  
  218.         // How many items did we get?
  219.  
  220.         {
  221.             InputFilenameNode *pnode = inputAVI->listFiles.AtHead();
  222.             InputFilenameNode *pnode_next;
  223.             int nFiles = 0;
  224.  
  225.             while(pnode_next = pnode->NextFromHead()) {
  226.                 ++nFiles;
  227.                 pnode = pnode_next;
  228.             }
  229.  
  230.             if (nFiles > 1)
  231.                 guiSetStatus("Autoloaded %d segments (last was \"%s\")", 255, nFiles, pnode->NextFromTail()->name);
  232.         }
  233.  
  234. //        SendMessage(hWndPosition, PCM_SETRANGEMIN, (BOOL)FALSE, inputAVI->videoSrc->lSampleFirst);
  235. //        SendMessage(hWndPosition, PCM_SETRANGEMAX, (BOOL)TRUE , inputAVI->videoSrc->lSampleLast);
  236.         RemakePositionSlider();
  237.         SendMessage(hWndPosition, PCM_SETFRAMERATE, 0, MulDiv(1000000, inputAVI->videoSrc->streamInfo.dwScale, inputAVI->videoSrc->streamInfo.dwRate));
  238.         SendMessage(hWndPosition, PCM_SETPOS, 0, 0);
  239.     } catch(...) {
  240.         CloseAVI();
  241.         throw;
  242.     }
  243. }
  244.  
  245. void AppendAVI(const char *pszFile) {
  246.     if (inputAVI) {
  247.         long lTail = inputAVI->videoSrc->lSampleLast;
  248.  
  249.         if (inputAVI->Append(pszFile)) {
  250.             if (inputSubset)
  251.                 inputSubset->addRange(lTail, inputAVI->videoSrc->lSampleLast - lTail);
  252.             RemakePositionSlider();
  253.         }
  254.     }
  255. }
  256.  
  257. void AppendAVIAutoscan(const char *pszFile) {
  258.     char buf[MAX_PATH];
  259.     char *s = buf, *t;
  260.     int count = 0;
  261.  
  262.     if (!inputAVI)
  263.         return;
  264.  
  265.     strcpy(buf, pszFile);
  266.  
  267.     while(*s) ++s;
  268.  
  269.     t = s;
  270.  
  271.     while(t>buf && t[-1]!='\\' && t[-1]!='/' && t[-1]!=':' && t[-1]!='.')
  272.         --t;
  273.  
  274.     if (t>buf && t[-1]=='.')
  275.         --t;
  276.  
  277.     if (t>buf)
  278.         --t;
  279.  
  280.     while(-1!=GetFileAttributes(buf) && inputAVI->Append(buf)) {
  281.         ++count;
  282.  
  283.         s = t;
  284.  
  285.         for(;;) {
  286.             if (s<buf || !isdigit(*s)) {
  287.                 memmove(s+2, s+1, strlen(s));
  288.                 s[1] = '1';
  289.                 ++t;
  290.             } else {
  291.                 if (*s == '9') {
  292.                     *s-- = '0';
  293.                     continue;
  294.                 }
  295.                 ++*s;
  296.             }
  297.             break;
  298.         }
  299.     }
  300.  
  301.     guiSetStatus("Appended %d segments (stopped at \"%s\")", 255, count, buf);
  302.  
  303.     if (count)
  304.         RemakePositionSlider();
  305. }
  306.  
  307. void CloseAVI() {
  308.     if (g_pInputOpts) {
  309.         delete g_pInputOpts;
  310.         g_pInputOpts = NULL;
  311.     }
  312.  
  313.     if (inputAVI) {
  314.         delete inputAVI;
  315.         inputAVI = NULL;
  316.     }
  317.     inputAudioAVI = NULL;
  318.     inputVideoAVI = NULL;
  319.  
  320.     if (inputSubset) {
  321.         delete inputSubset;
  322.         inputSubset = NULL;
  323.     }
  324.  
  325.     filters.DeinitFilters();
  326.     filters.DeallocateBuffers();
  327. }
  328.  
  329. void OpenWAV(char *szFile) {
  330.     CloseWAV();
  331.  
  332.     try {
  333.         inputAudioWAV = new AudioSourceWAV(szFile, g_dubOpts.perf.waveBufferSize);
  334.         if (!inputAudioWAV->init()) {
  335.             delete inputAudioWAV;
  336.             inputAudioWAV = NULL;
  337.         }
  338.  
  339.         audioInputMode = AUDIOIN_WAVE;
  340.     } catch(...) {
  341.         CloseWAV();
  342.         throw;
  343.     }
  344. }
  345.  
  346. void CloseWAV() {
  347.     if (inputAudioWAV) { delete inputAudioWAV; inputAudioWAV = NULL; }
  348. }
  349.  
  350. void SaveWAV(char *szFilename, bool fProp, DubOptions *quick_opts) {
  351.     if (!inputVideoAVI)
  352.         throw MyError("No input file to process.");
  353.  
  354.     SetAudioSource();
  355.  
  356.     try {
  357.         if (!(outputAVI = new AVIOutputWAV())) throw MyMemoryError();
  358.  
  359.         InitDubAVI(szFilename, TRUE, quick_opts, 0, fProp, 0, 0);
  360.     } catch(...) {
  361.         CloseNewAVI();
  362.         throw;
  363.     }
  364.     CloseNewAVI();
  365. }
  366.  
  367. ///////////////////////////////////////////////////////////////////////////
  368.  
  369. void CloseNewAVI() {
  370.     _RPT0(0,"Deleting output AVI...\n");
  371.     if (outputAVI) { delete outputAVI; outputAVI = NULL; }
  372. }
  373.  
  374. ///////////////////////////////////////////////////////////////////////////
  375.  
  376. void SaveAVI(char *szFilename, bool fProp, DubOptions *quick_opts, bool fCompatibility) {
  377.     try {
  378.         if (!(outputAVI = new AVIOutputFile()))
  379.             throw MyMemoryError();
  380.  
  381.         if (g_prefs.fAVIRestrict1Gb)
  382.             ((AVIOutputFile *)outputAVI)->set_1Gb_limit();
  383.  
  384.         ((AVIOutputFile *)outputAVI)->disable_os_caching();
  385.  
  386.         if (fCompatibility)
  387.             ((AVIOutputFile *)outputAVI)->disable_extended_avi();
  388.  
  389.         InitDubAVI(szFilename, FALSE, quick_opts, g_prefs.main.iDubPriority, fProp, 0, 0);
  390.     } catch(...) {
  391.         CloseNewAVI();
  392.         throw;
  393.     }
  394.     CloseNewAVI();
  395. }
  396.  
  397. void SaveStripedAVI(char *szFile) {
  398.     AVIStripeSystem *stripe_def = NULL;
  399.  
  400.     ///////////////
  401.  
  402.     SetAudioSource();
  403.  
  404.     if (!inputVideoAVI)
  405.         throw MyError("No input video stream to process.");
  406.  
  407.     try {
  408.         if (!(stripe_def = new AVIStripeSystem(szFile)))
  409.             throw MyMemoryError();
  410.  
  411.         if (!(outputAVI = new AVIOutputStriped(stripe_def)))
  412.             throw MyMemoryError();
  413.         else {
  414.             if (g_prefs.fAVIRestrict1Gb)
  415.                 ((AVIOutputStriped *)outputAVI)->set_1Gb_limit();
  416.  
  417.             InitDubAVI(NULL, FALSE, NULL, g_prefs.main.iDubPriority, false, 0, 0);
  418.         }
  419.     } catch(...) {
  420.         delete stripe_def;
  421.         throw;
  422.     }
  423.  
  424.     delete stripe_def;
  425. }
  426.  
  427. void SaveStripeMaster(char *szFile) {
  428.     AVIStripeSystem *stripe_def = NULL;
  429.  
  430.     ///////////////
  431.  
  432.     SetAudioSource();
  433.  
  434.     if (!inputVideoAVI)
  435.         throw MyError("No input video stream to process.");
  436.  
  437.     try {
  438.         if (!(stripe_def = new AVIStripeSystem(szFile)))
  439.             throw MyMemoryError();
  440.  
  441.         if (!(outputAVI = new AVIOutputStriped(stripe_def)))
  442.             throw MyMemoryError();
  443.         else {
  444.             if (g_prefs.fAVIRestrict1Gb)
  445.                 ((AVIOutputStriped *)outputAVI)->set_1Gb_limit();
  446.  
  447.             InitDubAVI(NULL, 2, NULL, g_prefs.main.iDubPriority, false, 0, 0);
  448.         }
  449.     } catch(...) {
  450.         delete stripe_def;
  451.         throw;
  452.     }
  453.  
  454.     delete stripe_def;
  455. }
  456.  
  457. void SaveSegmentedAVI(char *szFilename, bool fProp, DubOptions *quick_opts, long lSpillThreshold, long lSpillFrameThreshold) {
  458.     if (!inputVideoAVI)
  459.         throw MyError("No input file to process.");
  460.  
  461.     try {
  462.         if (!(outputAVI = new AVIOutputFile()))
  463.             throw MyMemoryError();
  464.  
  465.         ((AVIOutputFile *)outputAVI)->disable_os_caching();
  466.         ((AVIOutputFile *)outputAVI)->disable_extended_avi();
  467.         ((AVIOutputFile *)outputAVI)->setSegmentHintBlock(true, NULL, 1);
  468.  
  469.         InitDubAVI(szFilename, FALSE, quick_opts, g_prefs.main.iDubPriority, fProp, lSpillThreshold, lSpillFrameThreshold);
  470.     } catch(...) {
  471.         CloseNewAVI();
  472.         throw;
  473.     }
  474.     CloseNewAVI();
  475. }
  476.  
  477.  
  478. ///////////////////////////////////////////////////////////////////////////
  479.  
  480.  
  481. void SetSelectionStart(long ms) {
  482.     if (!inputVideoAVI)
  483.         return;
  484.  
  485.     g_dubOpts.video.lStartOffsetMS = ms;
  486.     SendDlgItemMessage(g_hWnd, IDC_POSITION, PCM_SETSELSTART, (WPARAM)TRUE, inputVideoAVI->msToSamples(ms));
  487. }
  488.  
  489. void SetSelectionEnd(long ms) {
  490.     if (!inputVideoAVI)
  491.         return;
  492.  
  493.     g_dubOpts.video.lEndOffsetMS = ms;
  494.     SendDlgItemMessage(g_hWnd, IDC_POSITION, PCM_SETSELEND, (WPARAM)TRUE,
  495.         (inputSubset ? inputSubset->getTotalFrames() : (inputVideoAVI->lSampleLast - inputVideoAVI->lSampleFirst)) - inputVideoAVI->msToSamples(ms));
  496. }
  497.  
  498. void RemakePositionSlider() {
  499.     if (!inputAVI) return;
  500.  
  501.     HWND hwndPosition = GetDlgItem(g_hWnd, IDC_POSITION);
  502.  
  503.     if (inputSubset) {
  504.         SendMessage(hwndPosition, PCM_SETRANGEMIN, (BOOL)FALSE, 0);
  505.         SendMessage(hwndPosition, PCM_SETRANGEMAX, (BOOL)TRUE , inputSubset->getTotalFrames());
  506.     } else {
  507.         SendMessage(hwndPosition, PCM_SETRANGEMIN, (BOOL)FALSE, inputAVI->videoSrc->lSampleFirst);
  508.         SendMessage(hwndPosition, PCM_SETRANGEMAX, (BOOL)TRUE , inputAVI->videoSrc->lSampleLast);
  509.     }
  510.  
  511.     if (g_dubOpts.video.lStartOffsetMS || g_dubOpts.video.lEndOffsetMS) {
  512.         SendMessage(hwndPosition, PCM_SETSELSTART, (BOOL)FALSE, inputVideoAVI->msToSamples(g_dubOpts.video.lStartOffsetMS));
  513.         SendMessage(hwndPosition, PCM_SETSELEND, (BOOL)TRUE , (inputSubset ? inputSubset->getTotalFrames() : (inputVideoAVI->lSampleLast - inputVideoAVI->lSampleFirst)) - inputVideoAVI->msToSamples(g_dubOpts.video.lStartOffsetMS));
  514.     } else {
  515.         SendMessage(hwndPosition, PCM_CLEARSEL, (BOOL)TRUE, 0);
  516.     }
  517. }
  518.